package org.slusk.thynwor.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;

import org.slusk.thynwor.corestructures.Drone;
import org.slusk.thynwor.corestructures.Environment;
import org.slusk.thynwor.corestructures.GridMap;
import org.slusk.thynwor.corestructures.Resource;
import org.slusk.thynwor.util.Coordinates;
import org.slusk.thynwor.util.Direction;

public class ThynworGraphics2 implements IThynworWindow {
	
	private Environment env;
	private JFrame frame;
	private JToggleButton tglbtnRunSimulation;
	private JButton btnReset;
	private Surface surface;
	
	public ThynworGraphics2(Environment e) {
		this.env = e;
		initialize();
		this.getFrame().setVisible(true);
	}

	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 500, 500);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JToolBar toolBar = new JToolBar();
		toolBar.setFloatable(false);
		frame.getContentPane().add(toolBar, BorderLayout.NORTH);
		
		tglbtnRunSimulation = new JToggleButton("Run Simulation");
		tglbtnRunSimulation.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				toggleRunSim();
			}
		});
		toolBar.add(tglbtnRunSimulation);
		
//		JButton btnChangeChromosome = new JButton("Change Chromosome");
//		btnChangeChromosome.addActionListener(new ActionListener() {
//			public void actionPerformed(ActionEvent e) {
//			}
//		});
//		toolBar.add(btnChangeChromosome);
		
//		btnReset = new JButton("Reset");
//		btnReset.addActionListener(new ActionListener() {
//			public void actionPerformed(ActionEvent e) {
//				reset();
//			}
//		});
//		toolBar.add(btnReset);
		
		surface = new Surface();
		frame.getContentPane().add(surface, BorderLayout.CENTER);
	}
	
	private void toggleRunSim() {
		if (tglbtnRunSimulation.isSelected()) {
			env.startSim();
		} else {
			env.stopSim();
		}
	}
	
	public JFrame getFrame() {
		return frame;
	}
	
	@Override
	public void dispose() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setMap(GridMap map) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		surface.update();
	}
	
	public void reset() {
		env.resetLayout();
		//surface = new Surface();
	}
	
	class Surface extends JPanel {
		
		//private Environment env;
		private HashMap<String,CoordsAndDir> currentModel;
		private HashMap<String,CoordsAndDir> transitionModel;
		private int tileWidth = 30;
		private int tileHeight = 30;
		private int horizOffset = 0;
		private int vertOffset = 0;
		
		public Surface() {
			
			setBackground(new Color(0,0,0));
			setForeground(new Color(255,255,255));
			currentModel = new HashMap<String,CoordsAndDir>();
			buildModel(currentModel);
		}
		
		private void buildModel(HashMap<String, CoordsAndDir> model) {
			model.clear();
			Coordinates scaledCoords;
			for (Resource res : env.getResourceList()){
				scaledCoords = new Coordinates(
						res.getCoordinates().x * tileWidth + horizOffset
						, res.getCoordinates().y * tileHeight + vertOffset);
				model.put("FOOD-" + res.getId(), new CoordsAndDir(scaledCoords, null));
			}
			for (Drone drone : env.getDroneList()){
				scaledCoords = new Coordinates(
						drone.getCoordinates().x * tileWidth + horizOffset
						, drone.getCoordinates().y * tileHeight + vertOffset);
				model.put("DRONE-" + drone.getId(), new CoordsAndDir(scaledCoords,drone.getOrientation()));
			}
		}
	
		public void update() {
			Updater u = new Updater(50, 50);
			Thread t = new Thread(u);
			t.start();
//			u.run();
		}
		
	    @Override
	    public void paintComponent(Graphics g) {
	    	
	        super.paintComponent(g);
	        
	        doDrawing(g);
	    }
	
		private void doDrawing(Graphics g) {
			Graphics2D g2d = (Graphics2D) g;
			
			// draw base
			int startx = 5 * tileWidth-15;
			int starty = 5 * tileHeight-15;
			int rectwidth = 5 * tileWidth;
			int rectheight = 4 * tileHeight+15;
			
			g2d.setColor(Color.BLUE);
			g2d.draw(new Rectangle2D.Double(startx, starty, rectwidth, rectheight));
			
			for (Entry<String,CoordsAndDir> entry : currentModel.entrySet()) {
				int x = entry.getValue().coords.x;
				int y = entry.getValue().coords.y;
				
				if (entry.getKey().startsWith("DRONE")){
					g2d.setColor(Color.WHITE);
					g2d.drawString("◊", x, y);
				} else {
					g2d.setColor(Color.GREEN);
					g2d.drawString("@", x, y);
				}
			}	
			
		}
		
		private class CoordsAndDir {
			public CoordsAndDir(Coordinates coords, Direction dir) {
				this.coords = coords;
				this.dir = dir;
			}
			public Coordinates coords;
			public Direction dir;
		}
	
		private class Updater implements Runnable {
			private double updateRate;
			private int pushInterval;
			private int numUpdates;
			
			public Updater(int frameRate, int lag) {
				this.updateRate= 1000.0/frameRate;
				this.pushInterval = env.getSimSpeed();
				this.numUpdates = (int) ((pushInterval - lag + 1) / updateRate);
				transitionModel = new HashMap<String,CoordsAndDir>();
				buildModel(transitionModel);
			}
			
			@Override
			public void run() {
				long beforeTime, elapsed, sleep, totalTime = 0;
				beforeTime = System.currentTimeMillis();
	            
				while (numUpdates > 0) {
					if (!cycle(numUpdates)) {
						break;
					}
					repaint();
					
					elapsed = System.currentTimeMillis() - beforeTime;
		            sleep = (long) (updateRate - elapsed);
		            //System.out.println("\t"+ System.currentTimeMillis() + ": Elapsed: " + elapsed + ", sleep: " + sleep + ", numUpdates:" + numUpdates);
		            totalTime+= elapsed+sleep;
		            if (sleep < 0) {
		                sleep = 1;
		            }
		            
					try {
		                Thread.sleep(sleep);
		            } catch (InterruptedException e) {}
					
					numUpdates--;
		            beforeTime = System.currentTimeMillis();
				}
				buildModel(currentModel);
				repaint();
				//System.out.println("*** Total time:" + totalTime);
			}
	
			private boolean cycle(int remainingUpdates) {
				int xTransition, xStep, yTransition, yStep;
				for (Entry<String,CoordsAndDir> entry : transitionModel.entrySet()) {
					CoordsAndDir cnd = currentModel.get(entry.getKey());
					if (cnd==null) return false;
					Coordinates currentCoords = cnd.coords;
					xTransition = entry.getValue().coords.x - currentCoords.x;
					yTransition = entry.getValue().coords.y - currentCoords.y;
					
					xStep = xTransition / remainingUpdates;
					yStep = yTransition / remainingUpdates;
					currentCoords.x += xStep;
					currentCoords.y += yStep;
					cnd.dir = entry.getValue().dir;
				}
				return true;
			}
			
		}
	
	}


}
